﻿using System;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Tszy.Unlimited.Data.AdoNet.Sql.Components
{
    /// <summary>
    /// 更新器。
    /// </summary>
    public interface IEditor<TSource> : IPropertyEditor<TSource>
    {
        /// <summary>
        /// 表达式上下文。
        /// </summary>
        public ExpressionContext Context { get; }

        #region 转换至属性更新器

        /// <summary>
        /// 转换至属性更新器。
        /// </summary>
        /// <returns>属性更新器。</returns>
        IPropertyEditor<TSource> ToPropertyEditor();

        #endregion 转换至属性更新器
    }

    /// <summary>
    /// 属性更新器。
    /// </summary>
    /// <typeparam name="TSource">实体类型。</typeparam>
    public interface IPropertyEditor<TSource> : IWhereEditor<TSource>, IExecuteEditor<TSource>
    {
        #region 设置属性

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, short>> predicate, short propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, short?>> predicate, short? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, int>> predicate, int propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, int?>> predicate, int? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, long>> predicate, long propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, long?>> predicate, long? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, float>> predicate, float propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, float?>> predicate, float? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, double>> predicate, double propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, double?>> predicate, double? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, decimal>> predicate, decimal propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, decimal?>> predicate, decimal? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, string>> predicate, string propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, bool>> predicate, bool propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, bool?>> predicate, bool? propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, DateTime>> predicate, DateTime propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetEnumProperty<TResult>(Expression<Func<TSource, TResult>> predicate, object propertyValue);

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> SetObjectProperty<TResult>(Expression<Func<TSource, TResult>> predicate, object propertyValue);

        /// <summary>
        /// 设置唯一约束。
        /// </summary>
        /// <returns>属性编辑器。</returns>
        IWhereEditor<TSource> SetUniqueProperty();

        #endregion 设置属性

        #region 累加属性

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, short>> predicate, short propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, short?>> predicate, short? propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, int>> predicate, int propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, int?>> predicate, int? propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, long>> predicate, long propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, long?>> predicate, long? propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, float>> predicate, float propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, float?>> predicate, float? propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, double>> predicate, double propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, double?>> predicate, double? propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, decimal>> predicate, decimal propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, decimal?>> predicate, decimal? propertyValue);

        /// <summary>
        /// 累加属性。
        /// </summary>
        /// <remarks>
        /// 将新的属性值累加到原属性值上。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, string>> predicate, string propertyValue);

        #endregion 累加属性
    }

    /// <summary>
    /// 属性更新条件筛选器。
    /// </summary>
    /// <typeparam name="TSource">实体类型。</typeparam>
    public interface IWhereEditor<TSource> : IExecuteEditor<TSource>
    {
        /// <summary>
        /// 条件过滤。
        /// </summary>
        /// <param name="predicate">条件。</param>
        /// <returns>属性更新条件筛选器。</returns>
        IWhereEditor<TSource> Where(Expression<Func<TSource, bool>> predicate);
    }

    /// <summary>
    /// 编辑处理器。
    /// </summary>
    /// <typeparam name="TSource">数据实体类型。</typeparam>
    public interface IExecuteEditor<TSource>
    {
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        bool Execute();

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        Task<bool> ExecuteAsync();
    }

    /// <summary>
    /// 更新方式。
    /// </summary>
    public enum ExecuteUpdateType
    {
        /// <summary>
        /// 覆盖。
        /// </summary>
        Set = 0,

        /// <summary>
        /// 累加。
        /// </summary>
        Accumulated = 1,
    }

    internal class ExecuteUpdateParameter
    {
        /// <summary>
        /// 属性类型。
        /// </summary>
        public Type PropertyType { get; set; }

        /// <summary>
        /// 属性名。
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 属性值。
        /// </summary>
        public object Value { get; set; }

        /// <summary>
        /// 更新方式。
        /// </summary>
        public ExecuteUpdateType UpdateType { get; set; }
    }
}